﻿using System;
using System.Collections.Generic;
using SimpleServiceBus.Bus;
using SimpleServiceBus.Bus.MessageManagement;
using SimpleServiceBus.Bus.MessageManagement.MessageHandling;
using SimpleServiceBus.Messages.ControlMessages;

namespace SimpleServiceBus
{
    public static class SsbExtensionMethods
    {
        public static bool IsMessageHandler(this Type t)
        {
            if (t.IsAbstract)
                return false;

            foreach (Type interfaceType in t.GetInterfaces())
            {
                Type messageType = interfaceType.GetPrimaryMessageTypeHandled();
                if (messageType != null)
                    return true;
            }

            return false;
        }

        public static Type GetPrimaryMessageTypeHandled(this Type t)
        {
            if (t.IsGenericType && !t.IsGenericTypeDefinition)
            {
                var handlerGenericType = t.GetGenericTypeDefinition();
                if(handlerGenericType == typeof(IMessageHandler<>)) {
                   Type[] args = t.GetGenericArguments();
                   return args[0];
                }
            }

            return null;
        }

        public static IList<Type> GetAllMessageTypesHandled(this Type t)
        {
            var found = new List<Type>();

            if (t.IsAbstract)
                return found;

            foreach (Type interfaceType in t.GetInterfaces())
            {
                Type messageType = interfaceType.GetPrimaryMessageTypeHandled();
                if (messageType != null)
                {
                    found.Add(messageType);
                }
            }

            return found;
        }

        public static bool CanSerialize(this Type t)
        {
            if (t == null)
                return false;

            if (t.IsInterface || t.IsAbstract)
                return false;

            if (!t.IsSerializable)
                return false;

            if (t.IsArray)
                return t.GetElementType().CanSerialize();

            return true;
        }

        public static Exception GetRootException(this Exception outerException)
        {
            Exception result = outerException;
            while (result.InnerException != null)
                result = result.InnerException;

            return result;
        }

        public static Type[] ExtractSerializableTypes(this IEnumerable<Type> typeList)
        {
            var types = new List<Type>();
            foreach (Type type in typeList)
            {
                if (type.CanSerialize())
                    types.Add(type);
            }
            return types.ToArray();
        }

        public static void RegisterMessageTypes(this IMessageTypeManagementService mgr,params Type[] messageTypes)
        {
            if (mgr != null && messageTypes != null)
            {
                foreach (Type type in messageTypes)
                    mgr.RegisterMessageType(type);
            }
        }
       
    }
}